﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel.Design;
using DevComponents.DotNetBar;
using DevComponents.DotNetBar.Controls;
using System.Drawing.Design;
using KP_CommonLibrary.KP_DataAccess;
using System.Data;
using KP_CommonLibrary.KP_ObjectReferences;
using KP_CommonLibrary.KP_CommonControls;
using System.Reflection;
namespace KP_CommonLibrary.KP_CoreUI
{
    [ProvideProperty("KPPropertyName", typeof(Control))]
    [ProvideProperty("KPDataMember", typeof(Control))]
    [ProvideProperty("KPValueType", typeof(Control))]
    [ProvideProperty("KPRequirement", typeof(Control))]
    [ProvideProperty("KPMessage", typeof(Control))]
    [ProvideProperty("KPAutoChangeState", typeof(Control))]
    [ProvideProperty("KPSourceIndex", typeof(Control))]
    [ProvideProperty("KPCustomValidate", typeof(Control))]
    [ProvideProperty("KPNullValue", typeof(Control))]
    
    public partial class KP_BindingController : Component, IExtenderProvider, ISupportInitialize
    {
        public string[] RelationTables { get; set; }
        bool isInitializing = false;
        Hashtable vhtControl;
        public Dictionary<Control, string> _TabWeight;

        public event EventHandler<CustomValidateEventArgs> CustomValidate;
        public KP_BindingController()
        {
            vhtControl = new Hashtable();
            _TabWeight = new Dictionary<Control, string>();
            InitializeComponent();
        }

        public KP_BindingController(IContainer container)
        {
            vhtControl = new Hashtable();
            container.Add(this);

            InitializeComponent();
        }

        public ContainerControl ContainerControl { get; set; }
        public override ISite Site
        {
            get { return base.Site; }
            set
            {
                base.Site = value;
                if (value == null)
                {
                    return;
                }

                IDesignerHost host = value.GetService(
                    typeof(IDesignerHost)) as IDesignerHost;
                if (host != null)
                {
                    IComponent componentHost = host.RootComponent;
                    if (componentHost is ContainerControl)
                    {
                        ContainerControl = componentHost as ContainerControl;
                    }
                }
            }
        }

        public event BindingControlHandler ControlBinding;

        protected new bool DesignMode
        {
            get
            {
                if (base.DesignMode)
                    return true;
                return LicenseManager.UsageMode == LicenseUsageMode.Designtime;
            }
        }
        #region IExtenderProvider Members

        public bool CanExtend(object extendee)
        {
            return (extendee is Control) &&
                !(extendee is Form) &&
                !(extendee is ToolBar) &&
                !(extendee is Panel) &&
                !(extendee is GroupBox) &&
                !(extendee is ToolStrip) &&
                !(extendee is IButtonControl) &&
                !(extendee is ButtonItem) &&
                !(extendee is PanelEx) &&
                !(extendee is Bar) &&
                !(extendee is GroupPanel)
                ;

            //  throw new NotImplementedException();
        }

        #endregion

        void OnCustomValidate(CustomValidateEventArgs e)
        {
            if (CustomValidate != null)
                CustomValidate(this, e);
        }
        public void WriteAllBinding()
        {
            IDictionaryEnumerator enumerator = this.vhtControl.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Control c = enumerator.Current as Control;
                BindingProperties b = EnsurePropertiesExists(enumerator.Current);
                WriteBinding(c);
            }
        }

        public void WriteBinding(Control c)
        {
            BindingProperties b = EnsurePropertiesExists(c);
            if (!String.IsNullOrEmpty(b.DataMember) && !String.IsNullOrEmpty(b.PropertyName))
            {

                if (c.DataBindings.Count > 0)
                {
                    for (int i = 0; i < c.DataBindings.Count; i++)
                    {
                        if (c.DataBindings[i].PropertyName == b.PropertyName)
                        {
                            c.DataBindings[i].WriteValue();
                        }
                    }
                }
            }
        }
        private BindingProperties EnsurePropertiesExists(object key)
        {
            if (vhtControl == null) vhtControl = new Hashtable();
            BindingProperties item = vhtControl[key] as BindingProperties;
            if (item == null)
            {
                item = new BindingProperties();
                vhtControl[key] = item;

            }
            return item;
        }
        #region DataMember


        [DefaultValue(false)]
        public void SetKPNullValue(Control ctrl, object value)
        {
            BindingProperties bp = EnsurePropertiesExists(ctrl);
            bp.NullValue = value;
        }
        public object GetKPNullValue(Control ctrl)
        {
            BindingProperties bp = EnsurePropertiesExists(ctrl);
            return bp.NullValue;
        }
        [DefaultValue(false)]
        public void SetKPCustomValidate(Control ctrl, bool value)
        {
            BindingProperties bp = EnsurePropertiesExists(ctrl);
            bp.CustomValidate = value;
        }
        public bool GetKPCustomValidate(Control ctrl)
        {
            BindingProperties bp = EnsurePropertiesExists(ctrl);
            return bp.CustomValidate;
        }
        [RefreshProperties(RefreshProperties.Repaint)]
        public void SetKPDataMember(Control ctrl, string value)
        {
            BindingProperties bp = EnsurePropertiesExists(ctrl);
            bp.DataMember = value;
            if (DesignMode && !isInitializing && !string.IsNullOrEmpty(value) && string.IsNullOrEmpty(bp.PropertyName))
                if (ctrl is ListControl)
                {
                    bp.PropertyName = "SelectedValue";
                }
                else
                    if (ctrl is KP_CommonLibrary.KP_CommonControls.NumericInput.MaskBox)
                        SetKPPropertyName(ctrl, "EditValue");
                    else if (ctrl is DevComponents.Editors.IntegerInput || ctrl is DevComponents.Editors.DoubleInput)
                        SetKPPropertyName(ctrl, "ValueObject");
                    else SetKPPropertyName(ctrl, "Text");

        }
        [DefaultValue("")]
        [Editor(typeof(ChoiceFieldEditor), typeof(UITypeEditor))]
        [RefreshProperties(RefreshProperties.Repaint)]
        public string GetKPDataMember(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).DataMember;
        }

        public bool ShouldSerializeKPDataMember(Control ctrl)
        {
            if (string.IsNullOrEmpty(EnsurePropertiesExists(ctrl).DataMember))
                return true;
            else
                return false;
        }
        public void ResetKPDataMember(Control ctrl)
        {
            SetKPDataMember(ctrl, string.Empty);
        }

        #endregion

        #region PropertyName

        public void SetKPPropertyName(Control ctrl, string value)
        {

            EnsurePropertiesExists(ctrl).PropertyName = value;
        }
        [DefaultValue("")]
        public string GetKPPropertyName(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).PropertyName;
        }

        public bool ShouldSerializePropertyName(Control ctrl)
        {
            if (string.IsNullOrEmpty(EnsurePropertiesExists(ctrl).PropertyName))
                return true;
            else
                return false;
        }
        public void ResetPropertyName(Control ctrl)
        {
            SetKPPropertyName(ctrl, string.Empty);
        }


        #endregion


        #region Requirement

        public void SetKPRequirement(Control ctrl, bool value)
        {

            EnsurePropertiesExists(ctrl).Requirement = value;
        }
        public bool GetKPRequirement(Control ctrl)
        {

            return EnsurePropertiesExists(ctrl).Requirement;

        }

        //public bool ShouldSerializeRequirement(Control ctrl)
        //{
        //    if (EnsurePropertiesExists(ctrl).Requirement)
        //        return false;
        //    else
        //        return true;
        //}
        //public void ResetRequirement(Control ctrl)
        //{
        //    SetRequirement(ctrl, false);
        //}


        #endregion
        #region AutoChangeState
        public void SetKPAutoChangeState(Control ctrl, bool value)
        {

            EnsurePropertiesExists(ctrl).AutoChangeState = value;
        }
        public bool GetKPAutoChangeState(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).AutoChangeState;
        }

        public bool ShouldSerializeKPAutoChangeState(Control ctrl)
        {
            if (EnsurePropertiesExists(ctrl).AutoChangeState)
                return false;
            else
                return true;
        }
        public void ResetKPAutoChangeState(Control ctrl)
        {
            SetKPAutoChangeState(ctrl, true);
        }
        #endregion
        #region ValueType

        public void SetKPValueType(Control ctrl, ValueType value)
        {

            EnsurePropertiesExists(ctrl).ValueType = value;
        }
        public ValueType GetKPValueType(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).ValueType;
        }

        public bool ShouldSerializeKPValueType(Control ctrl)
        {
            if (EnsurePropertiesExists(ctrl).ValueType != (ValueType.Text))
                return true;
            else
                return false;
        }
        public void ResetValueType(Control ctrl)
        {
            SetKPValueType(ctrl, ValueType.Text);
        }


        #endregion
        #region MessageRequirement
        public void SetKPMessage(Control ctrl, string value)
        {

            EnsurePropertiesExists(ctrl).MessageRequirement = value;
        }
        public string GetKPMessage(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).MessageRequirement;
        }

        public bool ShouldSerializeKPMessage(Control ctrl)
        {
            if (EnsurePropertiesExists(ctrl).MessageRequirement != "")
                return true;
            else
                return false;
        }
        public void ResetKPMessage(Control ctrl)
        {
            SetKPMessage(ctrl, "");
        }

        #endregion
        #region SourceIndex
        public void SetKPSourceIndex(Control ctrl, int value)
        {
            EnsurePropertiesExists(ctrl).SourceIndex = value;
        }

        public int GetKPSourceIndex(Control ctrl)
        {
            return EnsurePropertiesExists(ctrl).SourceIndex;
        }

        public bool ShouldSerializeKPSourceIndex(Control ctrl)
        {
            if (EnsurePropertiesExists(ctrl).SourceIndex != 0)
                return true;
            else
                return false;
        }
        public void ResetSourceIndex(Control ctrl)
        {
            SetKPSourceIndex(ctrl, 0);
        }

        #endregion

        public void ContainerChangeState(FormState e)
        {
            IEnumerator enumerator = vhtControl.Keys.GetEnumerator();

            while (enumerator.MoveNext())
            {

                if (EnsurePropertiesExists(enumerator.Current).AutoChangeState)
                {
                    //MessageBox.Show("OK");
                    ChangeStateOfControl((Control)enumerator.Current, e);
                }
            }
        }
        private void ChangeStateOfControl(Control c, FormState s)
        {
            try
            {
                switch (s)
                {
                    case FormState.Insert:
                    case FormState.Update:
                        if (c is TextBox)
                            (c as TextBox).ReadOnly = false;
                        else if (c is RichTextBox)
                            (c as RichTextBox).ReadOnly = false;
                        else
                            c.Enabled = true;
                        break;
                    case FormState.Normal:
                        if (c is TextBox)
                            (c as TextBox).ReadOnly = true;
                        else if (c is RichTextBox)
                            (c as RichTextBox).ReadOnly = true;
                        else
                            c.Enabled = false;
                        break;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Keeper Bindind controller Chang state Fail", ex);
            }
        }
        public void BindingControl()
        {
            string description = "";
            try
            {
                //  List<Control> lstControl = new List<Control>();
                // Dictionary<Control, string> a = new Dictionary<Control, string>();

                IContainerDataSource cds = ContainerControl as IContainerDataSource;
                if (cds == null)
                    throw new Exception("Kepper Controller say: Parent is not implement IContainerDataSource!");
                IEnumerator enumerator = vhtControl.Keys.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    BindingProperties b = EnsurePropertiesExists(enumerator.Current);
                    if (!String.IsNullOrEmpty(b.DataMember) && !String.IsNullOrEmpty(b.PropertyName))
                    {

                        //   lstControl.Add((Control)enumerator.Current);
                        Control c = enumerator.Current as Control;
                        if (!c.Created)
                        {
                            var method = c.GetType().GetMethod("CreateControl", BindingFlags.Instance | BindingFlags.NonPublic);
                            var parameters = method.GetParameters();
                            Debug.Assert(parameters.Length == 1, "Looking only for the method with a single parameter");
                            Debug.Assert(parameters[0].ParameterType == typeof(bool), "Single parameter is not of type boolean");

                            method.Invoke(c, new object[] { true });
                           // c.CreateControl();
                        }
                        description = string.Format("Binding control ID={0} PropertyName={1} DataMember={2}", c.Name, b.PropertyName, b.DataMember);
                        bool exists = false;
                        Binding bind=null;
                        if (c.DataBindings.Count > 0)
                        {
                            for (int i = 0; i < c.DataBindings.Count; i++)
                            {
                                if (c.DataBindings[i].PropertyName == b.PropertyName)
                                {
                                    if (c.DataBindings[i].DataSource == cds.GetSource(b.SourceIndex))
                                    {
                                        exists = true;
                                        bind=c.DataBindings[i];
                                        break;
                                    }
                                }
                            }
                        }
                        if (exists)
                        {
                            //if (ControlBinding != null)
                            //{
                            //    BindingControlArgs ba = new BindingControlArgs();
                            //    ba.Control = c;
                            //    ba.Binding = bind;
                            //    ControlBinding(this, ba);
                            //}
                            continue;
                        }
                        bind = new Binding(b.PropertyName, cds.GetSource(b.SourceIndex), b.DataMember);
                        if (b.NullValue != null)
                        {
                            bind.DataSourceNullValue = b.NullValue;
                            bind.NullValue = b.NullValue;
                        }
                        if (ControlBinding != null)
                        {
                            BindingControlArgs ba = new BindingControlArgs();
                            ba.Control = c;
                            ba.Binding = bind;
                            ControlBinding(this, ba);
                        }
                        c.DataBindings.Add(bind);
                        bind.ReadValue();
                        
                    }
                }
                //for (int i = 0; i < lstControl.Count; i++)
                //{
                //    BindingProperties b = EnsurePropertiesExists(enumerator.Current);
                //}
            }
            catch (Exception ex)
            {
                throw new Exception("Occur error when binding " + description, ex);
            }

        }
        public string[] ValidateRequirement()
        {
            List<Control> lstControl = new List<Control>();
            IEnumerator enumerator = vhtControl.Keys.GetEnumerator();
            List<String> lstMessage = new List<string>();
            bool calculatorTabWeight = false;
            if (_TabWeight == null)
            {
                _TabWeight = new Dictionary<Control, string>();
                calculatorTabWeight = true;

            }

            while (enumerator.MoveNext())
            {
                BindingProperties p = EnsurePropertiesExists(enumerator.Current);

                WriteBinding((Control)enumerator.Current);

                if (p.Requirement || p.CustomValidate)
                    lstControl.Add((Control)enumerator.Current);
                if (calculatorTabWeight)
                    _TabWeight.Add((Control)enumerator.Current, CalculatorTabWeight((Control)enumerator.Current));

            }
            lstControl.Sort(delegate(Control c1, Control c2)
            {
                string tabWeight1 = _TabWeight[c1];
                string tabWeight2 = _TabWeight[c2];
                if (tabWeight1.Length > tabWeight2.Length)
                {
                    tabWeight1 = tabWeight1.Substring(0, tabWeight2.Length);
                }
                else
                    if (tabWeight2.Length > tabWeight1.Length)
                        tabWeight2 = tabWeight2.Substring(0, tabWeight1.Length);
                return tabWeight1.CompareTo(tabWeight2);//c1.TabIndex.CompareTo(c2.TabIndex);
            });
            string validateInfo = "";
            try
            {
                for (int i = 0; i < lstControl.Count; i++)
                {
                    BindingProperties b = EnsurePropertiesExists(lstControl[i]);
                    Control c = lstControl[i];
                    validateInfo = string.Format("[{0}] Property {1} DataMember {2} Requirement {3} CustomValidate {4}",
                        c.Name, b.PropertyName, b.DataMember,b.Requirement,b.CustomValidate);
                    if (b.Requirement)
                    {
                        
                        if (IsEmptyValue(lstControl[i], b))
                        {
                            if (String.IsNullOrEmpty(b.MessageRequirement))
                            {
                                
                                if (c is TextBoxX)
                                {
                                    TextBoxX txt = c as TextBoxX;
                                    if (string.IsNullOrEmpty(txt.WatermarkText))
                                    {
                                        if (txt.Tag == null)
                                            lstMessage.Add("Chưa nhập giá trị cho " + b.DataMember);
                                        else
                                            lstMessage.Add(txt.Tag.ToString());
                                    }
                                    else
                                        lstMessage.Add(RemoveWatermarkText(txt.WatermarkText));
                                }

                            }
                            else
                                lstMessage.Add(b.MessageRequirement);
                        }
                    }
                    if (b.CustomValidate)
                    {
                        CustomValidateEventArgs arg = new CustomValidateEventArgs();
                        arg.BindingProperties = b;
                        arg.Control = lstControl[i];
                        arg.IsVaild = false;
                        arg.Message = "";
                        OnCustomValidate(arg);
                        if (!arg.IsVaild && !string.IsNullOrEmpty(arg.Message))
                        {
                            lstMessage.Add(arg.Message);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(validateInfo+"\n"+ex.Message, ex);
            }
            return lstMessage.ToArray();
        }
        private string CalculatorTabWeight(Control c)
        {
            StringBuilder sb = new StringBuilder();

            while (!(c.Parent is Form))
            {
                sb.Insert(0, "." + c.TabIndex.ToString());
                c = c.Parent;
            }

            if (c.Parent is Form)
                sb.Insert(0, c.TabIndex.ToString());
            return sb.ToString();

        }
        private string RemoveWatermarkText(string s)
        {
            if (s.StartsWith("nhập", StringComparison.InvariantCultureIgnoreCase))
                return s.Substring(4);
            return s;
        }
        private bool IsEmptyValue(Control c, BindingProperties b)
        {
            if (c is TextBox)
            {
                return string.IsNullOrEmpty((c as TextBox).Text);
            }
            if (c is ListControl)
            {
                int customIndex = 0;
                if (c.Tag != null && int.TryParse(c.Tag.ToString(),out customIndex))
                    return (c as ListControl).SelectedIndex == customIndex;
                return (c as ListControl).SelectedIndex < 0;
            }
            if (c is CheckedListBox)
            {
                return (c as CheckedListBox).CheckedIndices.Count == 0;
            }
            if (c is KP_ShortDateInput)
                return (c as KP_ShortDateInput).Value == DateTime.MinValue;

            if (!String.IsNullOrEmpty(b.PropertyName))
            {
                Type t = c.GetType();
                PropertyInfo pi = t.GetProperty(b.PropertyName);
                object obj = pi.GetValue(c, null);
                //object obj = TypeDescriptor.GetProperties(c)[b.PropertyName].GetValue(b);
                return obj == null || string.IsNullOrEmpty(obj.ToString());
            }
            return String.IsNullOrEmpty(c.Text);
        }
       public delegate void DelegateForeach(Control c,BindingProperties b);
        public void Foreach(DelegateForeach d)
        {
            IEnumerator enumerator = vhtControl.Keys.GetEnumerator();
            while (enumerator.MoveNext())
            {
                BindingProperties p = EnsurePropertiesExists(enumerator.Current);
                d(enumerator.Current as Control, p);
            }
        }

        #region ISupportInitialize Members

        public void BeginInit()
        {
            isInitializing = true;
        }

        public void EndInit()
        {
            isInitializing = false;
            if (!DesignMode)
                RelationTables = null;
        }

        #endregion
    }
    public enum ValueType
    {
        Text,
        Number,
        Money,
        Date,
        Time,
        DateTime,
        Image,
        Others
    }
    public class CustomValidateEventArgs : EventArgs
    {
        public BindingProperties BindingProperties { get; set; }
        public Control Control { get; set; }
        public string Message { get; set; }
        public bool IsVaild { get; set; }
        ~CustomValidateEventArgs()
        {
            BindingProperties = null;
            Control = null;
        }
    }
    public class BindingProperties
    {
        public BindingProperties()
        {
            AutoChangeState = false;
        }
        public string PropertyName { set; get; }
        public string DataMember { get; set; }
        public ValueType ValueType { get; set; }
        public bool Requirement { get; set; }
        public string MessageRequirement { get; set; }
        private bool _temp;
        public bool AutoChangeState { get { return _temp; } set { _temp = value; } }
        public int SourceIndex { get; set; }
        public bool CustomValidate { get; set; }
        public object NullValue { get; set; }

    }
    public delegate void BindingControlHandler(object sender, BindingControlArgs ba);
    public class BindingControlArgs : EventArgs
    {
        public Control Control { get; set; }
        public Binding Binding { get; set; }
    }

}
